package com.rpi.action;

import java.io.IOException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class PlaySoundAction implements Runnable, IGpioAction {

	private static Logger log = LoggerFactory.getLogger(PlaySoundAction.class);

	private String soundFile;
	private boolean stopped = false;
	private Thread thread = null;

	private Object stoppedSync = new Object();
	
	public PlaySoundAction(String soundFile) {
		this.soundFile = soundFile;
	}

	public String getSoundFile() {
		return soundFile;
	}

	public void setSoundFile(String soundFile) {
		this.soundFile = soundFile;
	}

	/* (non-Javadoc)
	 * @see com.rpi.gpio.IGpioAction#action()
	 */
	@Override
	public void action() {
		// Set stopped to false here, as maybe someone is holding the bell after
		// having it released once. Then a thread is already started and can
		// continue.
		setStopped(false);
		if (!isRinging()) {
			log.info("Start a bell thread for {}.", soundFile);
			thread = new Thread(this, "BellThread");
			thread.start();
		} else {
			log.info("Start ringing but bell thread is already running, don't start a new one.");
		}

	}

	/* (non-Javadoc)
	 * @see com.rpi.gpio.IGpioAction#actionDone()
	 */
	@Override
	public void actionDone() {
		setStopped(true);
		log.debug("Set stop flag for {}.", soundFile);

	}

	private boolean isRinging() {
		return (thread != null && thread.isAlive());

	}

	public void run() {
		log.debug("Run new thread for the bell.");
		boolean runOnce = false; //Run at least once
		while (!isStopped() || !runOnce) {
			String[] command = { "mpg321", soundFile };
			try {
				log.trace("ring the bell {}.", soundFile);
				Process ringing = Runtime.getRuntime().exec(command);
				int err = ringing.waitFor();
				if(err != 0) {
					log.warn("Ringing process finished with error code {}", err);
				}
			} catch (IOException e) {
				log.error("Async Bell failed to ring", e);
			} catch (RuntimeException ex) {
				log.error("Async Bell failed to ring", ex);
			} catch (InterruptedException e) {
				log.error("Async Bell thread interrupted", e);
				return;
			} finally {
				runOnce = true;
			}
		}
		log.debug("Bell thread finished.");
	}

	@Override
	public String toString() {
		return String.format("AsyncBell '%s'", soundFile);
	}

	private boolean isStopped() {
		synchronized(stoppedSync) {
			return stopped;
		}
	}
	
	private void setStopped(boolean stopped) {
		synchronized(stoppedSync) {
			this.stopped = stopped;
		}
	}
}
